package main

import (
	"encoding/json"
	"google.golang.org/protobuf/proto"
	"log"
	"net"
	"os"
	"server_cluster/common/config"
	"server_cluster/common/logger"
	"server_cluster/common/mysock"
	"server_cluster/common/protoc/pb"
	"sync"
	"time"
)

var totalSendPack [10000]int32
var totalRecvPack [10000]int32
var totalSendErrorPack [10000]int32
var totalRecvErrorPack [10000]int32

type clientTestConfig struct {
	MaxPackNum     int32  `json:"MaxPackNum,omitempty"`
	UidStart       int32  `json:"UidStart,omitempty"`
	UidEnd         int32  `json:"UidEnd,omitempty"`
	Token          string `json:"Token,omitempty"`
	ServerIp       string `json:"ServerIp,omitempty"`
	SendPacketTick int32  `json:"SendPacketTick,omitempty"`
}

var mycfg clientTestConfig
var wgClientTest sync.WaitGroup

func main() {
	logger.InitLogger("gate-client", "debug")
	defer logger.CloseLogger()

	file, err := os.OpenFile("./Robot.json", os.O_RDONLY, 0644)
	if err != nil {
		return
	}
	defer file.Close()

	buffer := make([]byte, 1024)

	// 读取文件内容
	n, err := file.Read(buffer)
	if err != nil {
		if err.Error() == "EOF" {
			logger.Error("End of file reached.")
		} else {
			logger.Error("Error reading file: %v", err)
		}
	}

	err = json.Unmarshal(buffer[:n], &mycfg)
	if err != nil {
		panic(err)
		return
	}

	for i := mycfg.UidStart; i <= mycfg.UidEnd; i++ {
		go SinglePlayerAction(int64(i), mycfg.Token)
	}
	time.Sleep(2 * time.Second)
	wgClientTest.Wait()

	var totalSendNum int32
	for _, num := range totalSendPack {
		totalSendNum += num
	}
	var totalRecvNum int32
	for _, num := range totalRecvPack {
		totalRecvNum += num
	}
	var totalSendErrorNum int32
	for _, num := range totalSendErrorPack {
		totalSendErrorNum += num
	}
	var totalRecvErrorNum int32
	for _, num := range totalRecvErrorPack {
		totalRecvErrorNum += num
	}
	logger.Info("TotalSendPack=%d TotalRecvPack=%d", totalSendNum, totalRecvNum)
	logger.Info("TotalSendErrorPack=%d", totalSendErrorNum)
	logger.Info("TotalRecvErrorNum=%d", totalRecvErrorNum)
}

func SinglePlayerAction(id int64, token string) {
	wgClientTest.Add(1)
	defer wgClientTest.Done()

	conn, err := net.Dial("tcp", mycfg.ServerIp)
	if err != nil {
		log.Println("connect fail.")
		return
	}
	defer conn.Close()

	u := pb.CS_Login{
		Uid:   id,
		Token: token,
	}
	data, _ := proto.Marshal(&u)
	var result uint16
	mybuf := mysock.Create()
	mybuf.Command = config.CS_Login
	mybuf.Ext = 1
	result = mybuf.WriteOut(conn, data)
	if result != config.OK {
		return
	}
	//log.Printf("send command=%d,length=%d,code=%d,ext=%d,session=%d", mybuf.Command, mybuf.Data_length, mybuf.Code, mybuf.Ext, mybuf.Session)

	var gachaCount int32
	var Session uint64
	for {
		result = mybuf.ReadFromOutSide(conn)
		if result != config.OK {
			if result == config.TIMEOUT {
				continue
			}
			log.Println("read result = ", result)
			break
		}
		//log.Printf("recv command=%d,length=%d,code=%d,ext=%d,uid=%d", mybuf.Command, mybuf.Data_length, mybuf.Code, mybuf.Ext, mybuf.Session)
		if onAction(id, conn, mybuf, &gachaCount, &Session) != 0 {
			break
		}
	}
}

func onAction(uid int64, conn net.Conn, buf *mysock.SockBuf, gachaCount *int32, Session *uint64) int32 {
	buf.Session = *Session
	totalRecvPack[int32(uid)-mycfg.UidStart]++
	if buf.Code != config.OK {
		totalRecvErrorPack[int32(uid)-mycfg.UidStart]++
		logger.Warn("Action Failed Command=%v,code = %v", buf.Command, buf.Code)
	}
	if totalSendPack[int32(uid)-mycfg.UidStart] >= mycfg.MaxPackNum {
		return -1
	}
	switch buf.Command {
	case config.SC_Login:
		user := pb.SC_Login{}
		proto.Unmarshal(buf.Data[mysock.HEAD_LEN:mysock.HEAD_LEN+buf.Data_length], &user)
		*Session = user.GetSession()
		buf.Session = *Session
		if buf.Session == 0 {
			logger.Warn("session fail.")
		}
		test := pb.CS_Create_Battle{
			GmFight:       false,
			BattleGroupId: 15000,
		}
		SendMsg(uid, config.CS_CREATE_BATTLE, &test, &conn, buf)
	case config.SC_CREATE_BATTLE:
		test := pb.CS_Battle_Over{Status: true}
		SendMsg(uid, config.CS_BATTLE_OVER, &test, &conn, buf)
	case config.SC_BATTLE_OVER:
		test := pb.CS_GmReq{GmCmd: "GMAddItem(514,1000)"}
		SendMsg(uid, config.CS_GmReq, &test, &conn, buf)
	case config.SC_GmRsp:
		test := pb.CS_DoGachaReq{
			GachaScheduleId: 2,
			GachaTimes:      1,
			DebugProbTest:   false,
		}
		SendMsg(uid, config.CS_DoGachaReq, &test, &conn, buf)
	case config.SC_DoGachaRsp:
		if *gachaCount < 50 {
			test := pb.CS_DoGachaReq{
				GachaScheduleId: 2,
				GachaTimes:      1,
				DebugProbTest:   false,
			}
			*gachaCount += test.GachaTimes
			SendMsg(uid, config.CS_DoGachaReq, &test, &conn, buf)
		} else {
			test := pb.CS_GetGachaInfoReq{}
			SendMsg(uid, config.CS_GetGachaInfoReq, &test, &conn, buf)
		}

	case config.SC_EnterSceneResp:
		test := pb.CS_Fetch{Type: config.Fetch_type_all}
		SendMsg(uid, config.CS_FETCH, &test, &conn, buf)
	case config.SC_FETCH:
		test := pb.CS_GetGachaInfoReq{}
		SendMsg(uid, config.CS_GetGachaInfoReq, &test, &conn, buf)
	case config.SC_GetGachaInfoRsp:
		test := pb.CS_EnterSceneReq{SceneId: 2000}
		SendMsg(uid, config.CS_EnterSceneReq, &test, &conn, buf)
	default:
	}
	return 0
}

func SendMsg(uid int64, cmdId uint32, msg proto.Message, conn *net.Conn, mybuf *mysock.SockBuf) {
	test_data, _ := proto.Marshal(msg)
	mybuf.Command = cmdId
	mybuf.Ext++
	result := mybuf.WriteOut(*conn, test_data)
	if result != config.OK {
		totalSendErrorPack[int32(uid)-mycfg.UidStart]++
		return
	}
	totalSendPack[int32(uid)-mycfg.UidStart]++
	time.Sleep(time.Millisecond * time.Duration(mycfg.SendPacketTick))
}
